/*++
  This file contains 'Framework Code' and is licensed as such
  under the terms of your license agreement with Intel or your
  vendor.  This file may not be modified, except as allowed by
  additional terms of your license agreement.
--*/
/*++
// **************************************************************************
// *                                                                        *
// *      Intel Restricted Secret                                           *
// *                                                                        *
// *      QPI Reference Code                                                *
// *                                                                        *
// *      ESS - Enterprise Silicon Software                                 *
// *                                                                        *
// *      Copyright (c) 2013 - 2015 Intel Corp.                             *
// *                                                                        *
// *      This program has been developed by Intel Corporation.             *
// *      Licensee has Intel's permission to incorporate this source code   *
// *      into their product, royalty free.  This source code may NOT be    *
// *      redistributed to anyone without Intel's written permission.       *
// *                                                                        *
// *      Intel specifically disclaims all warranties, express or           *
// *      implied, and all liability, including consequential and other     *
// *      indirect damages, for the use of this code, including liability   *
// *      for infringement of any proprietary rights, and including the     *
// *      warranties of merchantability and fitness for a particular        *
// *      purpose.  Intel does not assume any responsibility for any        *
// *      errors which may appear in this code nor any responsibility to    *
// *      update it.                                                        *
// *                                                                        *
// **************************************************************************
// **************************************************************************
// *                                                                        *
// *  PURPOSE: Conatins the logic for automated uniPhy recipe programming   *
// *                                                                        *
// *                                                                        *
// **************************************************************************
--*/

#include "PlatformHost.h"
#include "DataTypes.h"
#include "QpiLib.h"
#include "QpiMisc.h"
#include "SysHost.h"
#include "SysFunc.h"
#include "EvAutoRecipe.h"


// Contains the declaration for table QpiEvRecipeTablePtr
// This file is generated by running the script on given XLS file
#include "QpiEvRecipeTable_HSX.h"
#include "QpiEvRecipeTable_BDX.h"



STATIC BOOLEAN IsValidCpuType(struct sysHost *host, UINT32 ProcessorTypeMask)
{
    UINT8 curCpuType = host->var.common.cpuType;

    // 
    // Note: We don't have a wild card for cpuType in the automation 
    //
    if (((curCpuType == CPU_HSX) && (ProcessorTypeMask == HSX_SOCKET)) ||
        ((curCpuType == CPU_BDX) && (ProcessorTypeMask == BDX_SOCKET))) {
      return TRUE;
    }
    else {
      return FALSE;
    }
}


STATIC BOOLEAN IsValidSkuType(struct sysHost *host, UINT16 SkuTypeMask)
{
    UINT8 curSkuType = host->var.common.skuType;

    if (SkuTypeMask == WILDCARD_16) {
      return TRUE;  // When mask is 0xFFFF, return TRUE irrespective of current CPU SubType
    }

    if ((curSkuType == SKU_EN1 || curSkuType == SKU_EN2) && (SkuTypeMask & (1 << EN_SKU_TYPE))) {
      return TRUE;
    } else if ((curSkuType == SKU_EP || curSkuType == SKU_EXB) && (SkuTypeMask & (1 << EP_SKU_TYPE))) {
      return TRUE;
    } else if ((curSkuType == SKU_EXA) && (SkuTypeMask & (1 << EX_SKU_TYPE))) {
      return TRUE; 
    } else if ((curSkuType == SKU_DE) && (SkuTypeMask & (1 << DE_SKU_TYPE))) {
      return TRUE;
    } else {
      return FALSE;
    }
}


STATIC BOOLEAN IsValidStepping(struct sysHost *host, UINT8 Socket, UINT64 SteppingMask)
{
    UINT8 curCpuType = host->var.common.cpuType;
    UINT8 curStepping = host->var.common.stepping;  // stepping is based on the lowest nibble resulting from CPUID execution
    UINT8 curChopType = host->var.common.chopType[Socket];

    UINT32 BitPosition;
    UINT64_STRUCT steppingmask64, one64, result64;

    // Support restricted to Brickland and Grantley platforms only - in particular HSX and BDX. IVT is provided for sake of completeness only
    //
    UINT8  Mapping[MAX_CPU_TYPES][MAX_CHOP_TYPES][6] = {
                                                       { // CPU_IVT
                                                         //R0    S0
                                                         { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, // LCC  
                                                         //L0    M0
                                                         { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, // MCC  
                                                         //A0    A1    B0    B3    C0    D0  
                                                         { 0,    1,    4,    7,    8,    12 },  // HCC  
                                                         //Not Applicable
                                                         { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, // MCC-DE  
                                                         //Not Applicable
                                                         { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, // LCC-DE
                                                       },
                                                       { // CPU_HSX
                                                         //R0    S0
                                                         { 24,   28,   0xFF, 0xFF, 0xFF, 0xFF}, // LCC  
                                                         //L0    M0
                                                         { 16,   20,   0xFF, 0xFF, 0xFF, 0xFF}, // MCC  
                                                         //A0    B0    C0  
                                                         { 0,    4,    8,    0xFF, 0xFF, 0xFF}, // HCC  
                                                         //Not Applicable
                                                         { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, // MCC-DE  
                                                         //Not Applicable
                                                         { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, // LCC-DE
                                                       },
                                                       { // CPU_BDX
                                                         //R0    S0
                                                         { 24,   28,   0xFF, 0xFF, 0xFF, 0xFF}, // LCC  
                                                         //L0    M0
                                                         { 16,   20,   0xFF, 0xFF, 0xFF, 0xFF}, // MCC  
                                                         //A0    B0    C0  
                                                         { 0,    4,    8,    0xFF, 0xFF, 0xFF}, // HCC  
                                                         //Not Applicable
                                                         { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, // MCC-DE  
                                                         //T0    U0    V0
                                                         { 32,   36,   40,   0xFF, 0xFF, 0xFF}, // LCC-DE
                                                       }
                                                };

    if (SteppingMask == WILDCARD_64) {
      return TRUE;  // When mask is 0xFFFF_FFFF_FFFF_FFFF, return TRUE irrespective of current steppping
    }

    BitPosition = Mapping[curCpuType][curChopType][curStepping];

    if (BitPosition == 0xFF) {
      return FALSE;
    }

    // Prepare a 64-bit struct version for 1 so that LShiftUINT64 can be used
    one64.lo = 1;
    one64.hi = 0;

    // Prepare a 64-bit struct version of SteppingMask
    steppingmask64.lo = (UINT32) SteppingMask; 
    steppingmask64.hi = (UINT32) (SteppingMask >> 32);

    // Get a 64-bit struct version of (1 << BitPosition)
    result64 = LShiftUINT64(one64, BitPosition);

    if ((result64.lo & steppingmask64.lo) || (result64.hi & steppingmask64.hi)) {
      return TRUE;
    } else {
      return FALSE;
    }
}


STATIC BOOLEAN IsValidSocket(struct sysHost *host, UINT8 SocId, UINT32 SocketListMask)
{
    if (SocketListMask == WILDCARD_32) {
      return TRUE;  // When mask is 0xFFFF_FFFF, return TRUE irrespective of current CPU    
    }

    if (SocketListMask & (1 << SocId)) {
      return TRUE;
    } else {
      return FALSE;
    }
}


STATIC BOOLEAN IsValidPort(struct sysHost *host, UINT8 PortId, UINT32 PortListMask)
{
    if (PortListMask == WILDCARD_32) {
      return TRUE;  // When mask is 0xFFFF_FFFF, return TRUE irrespective of current CPU    
    }

    if (PortListMask & (1 << PortId)) {
      return TRUE;
    } else {
      return FALSE;
    }
}


STATIC BOOLEAN OverrideUniphyValues(struct sysHost *host, UINT8 Soc, UINT8 Link, UINT8 Type, UINT32 Addr, UINT32 Mask, UINT32 *Data)
{
  UINT32 capid0;

  if (Type != TYPE_QPI_IAR) {
    return FALSE;
  }

  capid0 = host->var.common.procCom[Soc].capid0;

  //
  // 4168554: Apply uniphy 6.00 if dcu_mode == 0 because it's concurrent change
  // w/ peak adder fuse change required for uniphy 6.00
  //
  if ((host->var.common.cpuType == CPU_HSX) &&
      ((capid0 & BIT30)  == 0)) { // dcu_mode (checking bit without structure)

    if (Type == TYPE_QPI_IAR) {
      if ((Mask == 0xF0) && (Addr == WINDOW1_ADDR(WINDOW1_IAR_IOVB_BCAST, IOVB_RX_CTLE2_0_0_QPIAGENT_DFX_PHY_IOVB_REG))) {
        *Data = 5;
        return TRUE;
      }
      
      if ((Mask == 0x0F) && (Addr == WINDOW1_ADDR(WINDOW1_IAR_IOVB_BCAST, IOVB_RX_CTLE2_0_0_QPIAGENT_DFX_PHY_IOVB_REG))) {
        *Data = (5 << 4);
        return TRUE;
      }

    } // Type is QPI_IAR
  } // cpuType and dca checks

  return FALSE;
}


QPI_STATUS
QpiEvAutoRecipe (
  struct sysHost      *host,
  QPI_SOCKET_DATA     *SocketData,
  UINT8               Socket,
  UINT8               LinkIndex
  )
/*++

Routine Description:
   This function loops through each entry in the QpiEvRecipeTablePtr of QpiEvAutoRecipeEntry.h file 
   and updates the registers based on processor type, subtype, bitrates and stepping conditions. 
   This function is called for all valid ports of all valid sockets.

Arguments:
   host  - Pointer to the system host (root) structure
   SocketData - Socket specific data structure
   Socket - SocId we are looking up
   Link - Link# on socket

Returns:
   Status

--*/
{
  UINT32      RegAddr32, Data = 0, OverriddenData = 0;
  UINT8       Bus, PortDevice, Function, UnitId;
  UINT8       WinSubType, WinRegAddr;
  UINT32      TableIndex, NumEntries;
  BOOLEAN     CpuTypeCmp, SkuTypeCmp, SteppingCmp, SocketTypeCmp, PortTypeCmp, LinkSpeedCmp;
  BOOLEAN     PrintDebug = FALSE;
  UINT32      LinkSpeed;
  UINT32      QpiEvRecipeTableSize = 0;
  CHAR8       TmpArea[HELP_STR_CHARS + 1];
  EV_RECIPE_HEADER *QpiEvHdrTablePtr = NULL;
  EV_RECIPE_ENTRY  *QpiEvRecipeTablePtr = NULL;

  // Point to the right EV Recipe Table
  //
  if (host->var.common.cpuType == CPU_HSX) {
    QpiEvHdrTablePtr = (EV_RECIPE_HEADER*) &QpiEvHdrTable_HSX;
    QpiEvRecipeTablePtr = (EV_RECIPE_ENTRY*) &QpiEvRecipeTable_HSX;
    QpiEvRecipeTableSize = sizeof(QpiEvRecipeTable_HSX);
  } else if (host->var.common.cpuType == CPU_BDX) {
    QpiEvHdrTablePtr = (EV_RECIPE_HEADER*) &QpiEvHdrTable_BDX;
    QpiEvRecipeTablePtr = (EV_RECIPE_ENTRY*) &QpiEvRecipeTable_BDX;
    QpiEvRecipeTableSize = sizeof(QpiEvRecipeTable_BDX);    
  } else {
    QpiDebugPrintInfo1((host, QPI_DEBUG_INFO1, "\n ; Automated uniphy EV recipe not supported for CPUs other than HSX and BDX"));
    QPI_ASSERT( FALSE, ERR_GENERAL_FAILURE, MINOR_ERR_GENERAL);
  }

  QpiDebugPrintInfo1((host, QPI_DEBUG_INFO1, "\n ; Starting QpiEvAutoRecipe "));
  
  // Verify the signature, before parsing the EVRecipe entries
  if (QpiEvHdrTablePtr->Signature != EV_AUTO_RECIPE_SIGNATURE) {
    QpiDebugPrintInfo1((host, QPI_DEBUG_INFO1, "\n ; Invalid or incorrect signature found. Aborting UniPhy programming ."));
    QPI_ASSERT( FALSE, ERR_GENERAL_FAILURE, MINOR_ERR_GENERAL);
  }
  
  PrintDebug = (QpiEvHdrTablePtr->DebugMode == 0) ? FALSE : TRUE;
  
  // Dump the EV header contents, if debug is enabled
  if (PrintDebug == TRUE) {
    QpiDebugPrintInfo1((host, QPI_DEBUG_INFO1, "\n ; ---- EV Header Dump <start> ----"));
    QpiDebugPrintInfo1((host, QPI_DEBUG_INFO1, "\n ; Signature : 0x%08X", QpiEvHdrTablePtr->Signature));
    // Copy to a local buffer with max limit control before printing
    MemSetLocal((UINT8*) TmpArea, 0, HELP_STR_CHARS + 1);
    MemCopy((UINT8*)TmpArea, (UINT8*)QpiEvHdrTablePtr->Revision, REV_STR_CHARS);
    QpiDebugPrintInfo1((host, QPI_DEBUG_INFO1, "\n ; Uniphy Version : %s", TmpArea));
    QpiDebugPrintInfo1((host, QPI_DEBUG_INFO1, "\n ; Entries count : %d", QpiEvHdrTablePtr->NumberEntries));
    // Copy to a local buffer with max limit control before printing
    MemSetLocal((UINT8*) TmpArea, 0, HELP_STR_CHARS + 1);
    MemCopy( (UINT8*)TmpArea, (UINT8*)QpiEvHdrTablePtr->HelperString, HELP_STR_CHARS);
    QpiDebugPrintInfo1((host, QPI_DEBUG_INFO1, "\n ; Info : %s", TmpArea));			
    QpiDebugPrintInfo1((host, QPI_DEBUG_INFO1, "\n ; ---- EV Header Dump <end> ----"));	
  }

  // Get the bus number for uncore bus
  Bus = host->var.common.busUncore[Socket];

  // Loop though all the recipe entries in QpiEvRecipeTablePtr and apply the recipe if applicable
  NumEntries = QpiEvRecipeTableSize/sizeof(EV_RECIPE_ENTRY);

  for (TableIndex = 0; TableIndex < NumEntries; TableIndex++) {
    //
    if (PrintDebug == TRUE) {
      QpiDebugPrintInfo1((host, QPI_DEBUG_INFO1, "\n ; Fetching EV Recipe Entry at index %d    [OK]", TableIndex)); 
    } // Print Debug

    // Verify if the Processor Type, SubType (SKU) and Stepping match with the EV Recipe Entry
    CpuTypeCmp = IsValidCpuType(host, QpiEvRecipeTablePtr[TableIndex].ProcessorType);
    SkuTypeCmp = IsValidSkuType(host, QpiEvRecipeTablePtr[TableIndex].Skus);
    SteppingCmp = IsValidStepping(host, Socket, QpiEvRecipeTablePtr[TableIndex].Steppings);
    SocketTypeCmp = IsValidSocket(host, Socket, QpiEvRecipeTablePtr[TableIndex].SocBitmap);
    PortTypeCmp = IsValidPort(host, LinkIndex, QpiEvRecipeTablePtr[TableIndex].PortBitmap);
    
    // Verify the link speed
    LinkSpeedCmp = FALSE;
    LinkSpeed = host->setup.qpi.PhyLinkPerPortSetting[Socket].Phy[LinkIndex].QpiLinkSpeed;

    if (QpiEvRecipeTablePtr[TableIndex].BitRates != WILDCARD_32) {
      if ((1 << LinkSpeed) & QpiEvRecipeTablePtr[TableIndex].BitRates){
         LinkSpeedCmp = TRUE;
      }
    } else {
      LinkSpeedCmp = TRUE;
    } // BitRates test

    // Print verbose info on reason for this entry to be applied or not
    if (PrintDebug == TRUE) {
      QpiDebugPrintInfo1((host, QPI_DEBUG_INFO1, "\n ; TableIndex %d : CpuTypeCmp=%d, SkuTypeCmp=%d, SteppingCmp=%d, LinkSpeedCmp=%d, SocketTypeCmp=%d, PortTypeCmp=%d",
                                TableIndex, CpuTypeCmp, SkuTypeCmp, SteppingCmp, LinkSpeedCmp, SocketTypeCmp, PortTypeCmp));
    }
  
    // Process the EV Recipe Entry only when its cpu type and stepping match the current processor's type and stepping
    if (CpuTypeCmp && SkuTypeCmp && SteppingCmp && LinkSpeedCmp && SocketTypeCmp && PortTypeCmp) {

      // Mapping between the port and device number, this could change please verify this and keep it updated
      // For HSX and BDX, QPI0 is at dev 8, QPI1 is at dev 9 and QPI2 is at dev 10
      PortDevice = LinkIndex + 8;
  
      // Check if this is CSR and IAR access. Program based on the type of access
      if (QpiEvRecipeTablePtr[TableIndex].AccessType == TYPE_CSR) {

        // Find the Function number from table of entries
        Function = (FLD_MASK( 3, 12) & QpiEvRecipeTablePtr[TableIndex].RegisterAddress) >> 12;

        // If Port 0 is inactive and we want to write to 1.9.7 i.e. DFX function of Port 1, we
        // multiplex the access to Port 0 to 1.8.7 space
        if ((PortDevice == 9 && Function == 7)) {
          if (SocketData->Cpu[Socket].LinkData[0].Valid == FALSE) {
            // Override the Port as 8
            PortDevice = 8;
            if (PrintDebug == TRUE) {
              QpiDebugPrintInfo1((host, QPI_DEBUG_INFO1, "\n ; Multiplexing the CSR accesses for 1.9.7 to 1.8.7 for TableIndex=%d\n", TableIndex));
            } // Print Debug
          } else {
            continue;
          } // Is link 0 is active
        } // 1.9.7 check

        // Compute the register address
        RegAddr32 = (host->var.common.mmCfgBase | (Bus << 20) | PortDevice << 15 | (QpiEvRecipeTablePtr[TableIndex].RegisterAddress & ~(FLD_MASK(12, 20) & ~(FLD_MASK(5, 15)))));

        // Fetch the register value
        //
        // Check register size and read data
        //
        switch (QpiEvRecipeTablePtr[TableIndex].RegisterSize) {
          case sizeof (UINT32):
            Data = *(volatile UINT32 *) RegAddr32;
            break;
          case sizeof (UINT16):
            Data = *(volatile UINT16 *) RegAddr32;
            break;
          case sizeof (UINT8):
            Data = *(volatile UINT8 *) RegAddr32;
            break;
          default:
            FatalError (host, 0, 0);
            break;
        } // switch case
        if (PrintDebug == TRUE) {
          QpiDebugPrintInfo1((host, QPI_DEBUG_INFO1, "\n ; CSR Read access for TableIndex=%d, RegAddr32=0x%08X, Data=0x%08X.\n", TableIndex, RegAddr32, Data)); 
        } // Print Debug

        // Update the data with the values from the EV Recipe
        Data = ((Data & QpiEvRecipeTablePtr[TableIndex].FieldMask) | QpiEvRecipeTablePtr[TableIndex].Data);

        // Write the data
        switch (QpiEvRecipeTablePtr[TableIndex].RegisterSize) {
          case sizeof (UINT32):
            *(volatile UINT32 *) RegAddr32 = Data;
            break;

          case sizeof (UINT16):
            *(volatile UINT16 *) RegAddr32 = (UINT16) Data;
            break;

          case sizeof (UINT8):
            *(volatile UINT8 *) RegAddr32 = (UINT8) Data;
            break;

          default:
            FatalError (host, 0, 0);
            break;
        } // switch case
        if (PrintDebug == TRUE) {
          QpiDebugPrintInfo1((host, QPI_DEBUG_INFO1, "\n ; CSR Write access for TableIndex=%d, RegAddr32=0x%08X, Data=0x%08X.\n", TableIndex, RegAddr32, Data)); 
        } // Print Debug
    
        // Validate the register value by reading it
      } else if (QpiEvRecipeTablePtr[TableIndex].AccessType == TYPE_QPI_IAR) {

        RegAddr32 = QpiEvRecipeTablePtr[TableIndex].RegisterAddress;
        WinSubType = WINDOW1_ACCESS_SUB_TYPE(RegAddr32);
        WinRegAddr = WINDOW1_ACCESS_REG_ADDR(RegAddr32);

        // Read the IOVB broadcast or IOVC registers first into Data
        if (WinSubType == WINDOW1_IAR_IOVB_BCAST) {
          // Not sure why this is required.
          if (LinkIndex == 1) {
            UnitId = 0;     // for port 1
          } else {
            UnitId = 1;     // for port 0 or 2
          }

          Data = QpiReadIar (host, Socket, LinkIndex, UnitId, WinRegAddr);
        } else if (WinSubType == WINDOW1_IAR_IOVC) {
          Data = QpiReadIar (host, Socket, LinkIndex, QPILIB_IAR_IOVC, WinRegAddr);
        } else {
          QpiDebugPrintInfo1((host, QPI_DEBUG_INFO1, "\n ; Aborting. Don\'t know to apply EVEntry at TableIndex=%d, sub-type=%u, Unknown sub-type.", TableIndex, WinSubType));
          FatalError( host, 0, 0);
        } // WinSubType checks

        if (PrintDebug == TRUE) {
          QpiDebugPrintInfo1((host, QPI_DEBUG_INFO1, "\n ; IAR Read Access for TableIndex=%d, RegAddr32=0x%08X, WinSubType=0x%02X, WinRegAddr=0x%02X, Data=0x%02X\n", TableIndex, RegAddr32, WinSubType, WinRegAddr, Data)); 
        } // Print Debug

        // Update the data with the values from the EV Recipe or overridden values
        if (OverrideUniphyValues(host, Socket, LinkIndex, QpiEvRecipeTablePtr[TableIndex].AccessType, RegAddr32, QpiEvRecipeTablePtr[TableIndex].FieldMask, &OverriddenData)) {
          if (PrintDebug == TRUE) {
            QpiDebugPrintInfo1((host, QPI_DEBUG_INFO1, "\n ; Match with Overrides Table.Applying OverriddenData=0x%08X instead of tabular data.\n", OverriddenData));
          } // Print Debug

          Data = ((Data & QpiEvRecipeTablePtr[TableIndex].FieldMask) | OverriddenData);
        } else {
           Data = ((Data & QpiEvRecipeTablePtr[TableIndex].FieldMask) | QpiEvRecipeTablePtr[TableIndex].Data);
        } // OverrideUniphyValues check

        // Write the IOVB broadcast or IOVC registers back
        if (WinSubType == WINDOW1_IAR_IOVB_BCAST) {
          QpiWriteIar (host, Socket, LinkIndex, QPILIB_IAR_BCAST, WinRegAddr, (UINT8)Data);
        } else if (WinSubType == WINDOW1_IAR_IOVC) {
          QpiWriteIar (host, Socket, LinkIndex, QPILIB_IAR_IOVC, WinRegAddr, (UINT8)Data);
        } else {
          QpiDebugPrintInfo1((host, QPI_DEBUG_INFO1, "\n ; Aborting. Don\'t know to apply EVEntry at TableIndex=%d, sub-type=%u, Unknown sub-type.", TableIndex, WinSubType));
          FatalError( host, 0, 0);
        }

        if (PrintDebug == TRUE) {
          QpiDebugPrintInfo1((host, QPI_DEBUG_INFO1, "\n ; IAR Write Access for TableIndex=%d, RegAddr32=0x%08X, WinSubType=0x%02X, WinRegAddr=0x%02X, Data=0x%02X\n", TableIndex, RegAddr32, WinSubType, WinRegAddr, Data));
        } // Print Debug

       } else {
         QpiDebugPrintInfo1((host, QPI_DEBUG_INFO1, "\n ; Aborting. Don\'t know to apply EVEntry at TableIndex=%d, access type=%u, Unknown access type.", TableIndex, QpiEvRecipeTablePtr[TableIndex].AccessType));
         FatalError( host, 0 , 0);
       } // AccessType checks for CSR and QPI IAR

      } else {
        if (PrintDebug == TRUE) {
          QpiDebugPrintInfo1((host, QPI_DEBUG_INFO1, "\n ; Not applying. EVRecipe checks failed for EVEntry at TableIndex=%d", TableIndex));
        } // Print Debug
      } // CpuTypeCmp && SkuTypeCmp && SteppingCmp && LinkSpeedCmp checks 
  } // for loop

  QpiDebugPrintInfo1((host, QPI_DEBUG_INFO1, "\n ; End of EV Recipe Function ."));
  return QPI_SUCCESS;
}

